/**
 * 标准IEC103协议，只需要在南自协议基础之上加上报文头尾和检验和 (68H L L 68H CODE ADDR ASDU CS 16)
 * 次类的职责负责构造 asdu 之外的部分，并并入asdu后形成标准103协议报文
 *
 * 读取定值流程：
 * 1.初始化通信单元-> 2.复位帧计数-> 3.asdu命令读组信息  -> 4.召唤1级数据（固定帧）->5.召唤1级数据（连续直到收到保护提示没有）<- (保护发送没有可以读的数据了，一个请求数据读完了)
 *  以上过程除了第3步读命令需要构造变长报文，其它均为固定帧，根据地址（一般01）和 和固定的控制域构造的固定帧
 * */

#ifndef SZNR103CONSTRUCTER_H
#define SZNR103CONSTRUCTER_H
#include <QString>
#include <QByteArray>
#include "SZNR/SZNR103_Type.h"
#include "PacketConstructer.h"

class SZNR103Constructer
{
public:
    SZNR103Constructer();
    ~SZNR103Constructer();


    // 构造有个带有asdu的报文, 标准的只需要在南自的103基础上加报文头尾
    // 参数: 16进制字符数组asdu, 控制域（需要动态变化）， 地址域（cpu地址号，01即可， 0~254设备地址， 255 广播地址）
    // 返回值： 一个完整的报文
    QByteArray getVariableFrame(QByteArray& asdu, QByteArray& addr, int funCodeIndex);

    // 与保护设备通信的时候先复位通信单元，然后复位帧计数
    QByteArray constructRCU(QByteArray addr);  //功能序号 0， 服务通信单元
    QByteArray constructRFB(QByteArray addr);  //  复位帧计数

    // 参数: 1.地址域 2.控制域
    QByteArray constructPL1(QByteArray& addr);  // 召唤1级数据code = "01FCB11011",
    QByteArray constructPL2(QByteArray& addr, QByteArray& code);  // 召唤1级数据 code = "01FCB01001"
    QByteArray constructRLK(QByteArray& addr, QByteArray& code);    // 请求链路数据 coed="01fcb01001

    //构造控制域 8位位组的构造, 控制系统->保护， 参数: 功能码序号, 始终PRM=1（数据流向为控制系统->保护）
    QByteArray constructCode(int funCodeIndex);

    // 客户端使用开放的接口
    QByteArray constructReadTitles(QString& addr);
    QByteArray constructGetBillInfo(QString& addr, QString& groupNo, QString& kod);

private:
    static SZNR103Constructer *m_sznrConstructer;

    //参数 ：控制域+ 地址域   + asdu ，16进制字符数组形式, 固定帧没有asdu
    static uint8_t SumCheck( const QByteArray& packet);

    static QByteArray sumcheck( const QByteArray& packet);

    // 根据报文的 地址域、控制域、asdu 算出 校验和
    uint8_t SumCheck( const QString& packet, int32_t length );

    //计算报文长度, asdu 长度+2， 参数 asdu
     uint8_t LenCal(const QByteArray& packet);

    // 改变帧计数位fcb 第6个位，取反, 参数: 控制域16进制字符数组 返回：控制域
    QByteArray changeCtrl(QByteArray& code);

    QByteArray m_addr = "ff";  // 报文apci部分的地址域  0~254 设备地址， 255：广播地址

    // 控制域具体构造 ， D3~D0 为功能码  , D5 帧计数位（每一次新的请求响应 取反此位）， D4 帧计数有效位变化是否有效， 0 - 无效， 1 - 有效
    // 1.主-》从  ，即控制系统发给保护设备
    // D7 D6 D5 D4 D3 D2 D1 D0
    // 0  1
    QByteArray CtrlMaster2Slave = "01000000";

    // 1.从 -> 主
    // D7 D6 D5 D4 D3 D2 D1 D0
    // 0  0
    QByteArray CtrlSlave2Master = "00000000";

    //asdu 构造
    PacketConstructer *m_asduConstructer;

    bool m_fcb = true;   // code[5] 控制域 fcb 每次使用都要取反, 可以将 fcb 放到 Connection 类，发送的时候检查

};

#endif // SZNR103CONSTRUCTER_H
